package cz.proks.bank.dao.impl;

import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import cz.proks.bank.dao.BaseGenericDao;

@Repository
@Transactional
@Scope("prototype")
public class BaseGenericDaoImpl<T extends Serializable, PK extends Serializable> implements BaseGenericDao<T, PK>{
	private final Logger log = Logger.getLogger(getClass());
	
	@PersistenceContext
	private EntityManager entityManager;
	
	private Class<T> domainClass;	
		
	protected BaseGenericDaoImpl(Class<T> domainClass) {		
		this.domainClass = domainClass;
	}	
	
	@Override
	@Transactional(readOnly = true)
	public long count() {
		log.debug("count():: Start");
		
		Query query = entityManager.createQuery("SELECT COUNT(*) FROM " + domainClass.getName());
		long count = (Long) query.getSingleResult();
		
		log.debug("count():: Exit with count " + count);
		return count;
	}

	@Override
	@Transactional(readOnly = true)
	public T get(PK id) {
		log.debug("get():: Start with id = '" + id + "'");
		
		T entity = entityManager.find(domainClass, id);
		
		log.debug("get():: Exit with entity '" + entity + "'");
		return entity;		
	}
		
	@Override	
	public T create(T entity) {		
		log.debug("save():: Saving entity '" + entity + "'");
		
		entityManager.persist(entity);
				
		log.debug("save():: Exit with entity '" + entity + "'");
		return entity;		
	}
	
	@Override	
	public T update(T entity) {	
		log.debug("update():: Merging entity '" + entity + "'");
		
		entity = entityManager.merge(entity);
		
		log.debug("update():: Exit with entity '" + entity + "'");
		return entity;		
	}

	@Override
	public void delete(T entity) {
		log.debug("delete():: Start with entity '" + entity + "'");
		
		entityManager.remove(entity);
		
		log.debug("delete():: Exit");
	}

	@Override
	public void deleteById(PK id) {
		log.debug("delete():: Start with id = '" + id + "'");
		
		T entity = get(id);
		entityManager.remove(entity);
		
		log.debug("delete():: Exit");
	}	
	
	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = true)
	public List<T> listAll() {		
		log.debug("listAll():: Start");
		
		List<?> list = new LinkedList<T>();
				
		Query query = entityManager.createQuery("FROM " + domainClass.getName());
		list = query.getResultList();		
		
		log.debug("listAll():: Exit with " + (list == null ? "null list" : "collection of " + list.size() + " item(s)"));
		return (List<T>) list;
	}
}
